#!/Library/Frameworks/Python.framework/Versions/3.4/bin/python3
from optparse import OptionParser
import sys
import time
import tkinter as tk
import webcolors as wc
from tkinter import ttk

class ColorNode (tk.Frame):
    # basic Colour Node class
    def __init__(self,master=None,input=None,name="def_node"):
        tk.Frame.__init__(self,master)
        self.name = name
        self.input = input
        self.output = {"comp":"#FFFFFF","rate":0}
        self.prev_out_rate = 0
        self.max_volume = 100
        self.volume = 10
        self.baseWidgets()
    
    def tick(self):
        pass
    
    def baseWidgets(self):
        # grey background and name label
        self["bg"] = "#eee"
        self.name_lab = ttk.Label(self,text="Tag: {}".format(self.name))
        self.pack()
        self.name_lab.pack()

class ColorSource(ColorNode):
    # Colour source. Single Ouput. No Input
    def __init__(self,master=None,name="def_node",color=(80,100,200),rate=5):
        ColorNode.__init__(self,master,None,name)
        self.output["comp"] = wc.rgb_to_hex(color)
        self.output["rate"] = rate
        self.createWidgets()

    def createWidgets(self):
        self.output_label = tk.Label(self,text="Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"]), background=self.output["comp"])

        self.txt_ent = ttk.Entry(self)
        self.comp_but = ttk.Button(self)
        self.comp_but["text"] = "Set Color"
        self.comp_but["style"] = "A.TButton"
        self.comp_but["command"] = self.set_color
        
        self.rate_but = ttk.Button(self, text="Set Rate", style="A.TButton", command=self.set_rate)
                                                                   
        self.comp_but.pack(side="left")
        self.rate_but.pack(side="left")
        self.output_label.pack(side="bottom")
        self.txt_ent.pack(side="bottom")

    def set_color(self):
        try:
            self.output["comp"] = self.txt_ent.get()
            self.output_label["text"] = "Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"])
            self.output_label["background"] = self.output["comp"]
        except tk.TclError as err:
            print(err)

    def set_rate(self):
        self.output["rate"] = int(self.txt_ent.get())
        self.output_label["text"] = "Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"])

class ColorTank(ColorNode):
    def __init__(self,master=None,input=None,name="def_node"):
        ColorNode.__init__(self,master,input,name)
        self.createWidgets()
    
    def createWidgets(self):
        #self.input_label = tk.Label(self,text="Input\nRate: {} Color: {}".format(self.input["rate"],self.input["comp"]), background=self.input["comp"])
        self.level_label = tk.Label(self,text="Level: {}/{}".format(self.volume,self.max_volume))
        self.output_label = tk.Label(self,text="Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"]), background=self.output["comp"])
        
        self.txt_ent = ttk.Entry(self)
        self.txt_ent["width"] = 20
        
        self.rate_but = ttk.Button(self, text="Set Rate", style="A.TButton", command=self.set_rate)
        
        self.rate_but.pack(side="left")
        #self.input_label.pack(side="top")
        self.level_label.pack()
        self.output_label.pack(side="bottom")
        self.txt_ent.pack(side="left")
    
    def tick(self):
        # Set values
        self.in_color = wc.hex_to_rgb(self.input["comp"])
        self.in_color = tuple( x*self.input["rate"]/(self.volume + self.input["rate"]) for x in self.in_color )
        self.cur_color = wc.hex_to_rgb(self.output["comp"])
        self.cur_color = tuple (x*self.volume/(self.volume + self.input["rate"]) for x in self.cur_color)
        self.output["comp"] = wc.rgb_to_hex(tuple(clamp_n(sum(x)) for x in zip(self.in_color,self.cur_color)))
        self.volume += self.input["rate"]
        self.volume -= int(self.output["rate"])
        if self.volume <= 0:
            self.volume = 1
            self.prev_out_rate = self.output["rate"]
            self.output["rate"] = 0
        elif self.volume > self.max_volume:
            self.prev_out_rate = self.output["rate"]
            self.output["rate"] += self.volume - self.max_volume
            self.volume = self.max_volume
        
        #print(in_color, cur_color, wc.hex_to_rgb(self.output["comp"]))
        
        # Update labels
        #self.input_label["background"] = self.input["comp"]
        #self.input_label["text"] = "Input\nRate: {} Color: {}".format(self.input["rate"],self.input["comp"])
        self.level_label["text"] = "Level\nLevel: {}/{}".format(self.volume,self.max_volume)
        if (self.volume > (self.max_volume - self.max_volume/10)):
            self.level_label["bg"] = "red"
        elif (self.volume > self.max_volume/2):
            self.level_label["bg"] = "yellow"
        elif (self.volume < self.max_volume/10):
            self.level_label["bg"] = "lightblue"
        else:
            self.level_label["bg"] = "white"
        self.output_label["text"] = "Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"])
        self.output_label["bg"] = self.output["comp"]

    def set_rate(self):
        self.output["rate"] = int(self.txt_ent.get())
        self.output_label["text"] = "Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"])

class ColorShifter(ColorNode):
    def __init__(self,master=None,input=None,name="def_node"):
        ColorNode.__init__(self,master,input,name)
        self.color_shift = (2,2,2)
        self.createWidgets()
    
    def createWidgets(self):
        #self.input_label = tk.Label(self,text="Input\nRate: {} Color: {}".format(self.input["rate"],self.input["comp"]), background=self.input["comp"])
        self.level_label = tk.Label(self,text="Level: {}/{}".format(self.volume,self.max_volume))
        self.output_label = tk.Label(self,text="Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"]), background=self.output["comp"])
        
        self.txt_ent = ttk.Entry(self)
        self.txt_ent["width"] = 20
        
        self.rate_but = ttk.Button(self, text="Set Rate", style="A.TButton", command=self.set_rate)
        self.shift_but = ttk.Button(self, text="Set Shift", style="A.TButton", command=self.set_shift)
        
        self.red_slide = ttk.Scale(self, from_=16, to=-16,
                                   command=self.set_shift_r,
                                   length=150)
        self.green_slide = ttk.Scale(self, from_=16, to=-16,
                                     command=self.set_shift_g,
                                     length=150)
        self.blue_slide = ttk.Scale(self, from_=16, to=-16,
                                    command=self.set_shift_b,
                                    length=150)
        
        self.red_slide.pack()
        self.green_slide.pack()
        self.blue_slide.pack()
        
        self.rate_but.pack(side="left")
        self.shift_but.pack(side="left")
        #self.input_label.pack(side="top")
        self.level_label.pack()
        self.output_label.pack(side="bottom")
        self.txt_ent.pack(side="left")
    
    def tick(self):
        # Set values
        self.in_color = wc.hex_to_rgb(self.input["comp"])
        self.in_color = tuple( x*self.input["rate"]/(self.volume + self.input["rate"]) for x in self.in_color )
        self.cur_color = wc.hex_to_rgb(self.output["comp"])
        self.cur_color = tuple (x*self.volume/(self.volume + self.input["rate"]) for x in self.cur_color)
        self.output["comp"] = wc.rgb_to_hex(tuple(clamp_n(sum(x)) for x in zip(self.in_color,self.cur_color,self.color_shift)))
        print("tick:",self.color_shift)
        self.volume += self.input["rate"]
        self.volume -= int(self.output["rate"])
        if self.volume <= 0:
            self.volume = 1
            self.output["rate"] = 0
        elif self.volume > self.max_volume:
            self.output["rate"] += self.volume - self.max_volume
            self.volume = self.max_volume
        
        #print(in_color, cur_color, wc.hex_to_rgb(self.output["comp"]))
        
        # Update labels
        if (self.volume > (self.max_volume - self.max_volume/10)):
            self.level_label["bg"] = "red"
        elif (self.volume > self.max_volume/2):
            self.level_label["bg"] = "yellow"
        elif (self.volume < self.max_volume/10):
            self.level_label["bg"] = "lightblue"
        else:
            self.level_label["bg"] = "white"
        #self.input_label["background"] = self.input["comp"]
        #self.input_label["text"] = "Input\nRate: {} Color: {}".format(self.input["rate"],self.input["comp"])
        self.level_label["text"] = "Level\nLevel: {}/{}".format(self.volume,self.max_volume)
        self.output_label["text"] = "Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"])
        self.output_label["bg"] = self.output["comp"]

    def set_shift(self):
        self.tu = self.txt_ent.get().strip("()").split(",")
        self.tu = tuple( int(x) for x in self.tu )
        self.color_shift = self.tu[:]
        print("SS func:",self.color_shift)
    
    def set_shift_r(self, val):
        self.color_shift = tuple( (float(val), self.color_shift[1],self.color_shift[2]) )

    def set_shift_g(self, val):
        self.color_shift = tuple( (self.color_shift[0], float(val),self.color_shift[2]) )
    
    def set_shift_b(self, val):
        self.color_shift = tuple( (self.color_shift[0], self.color_shift[1],float(val)) )

    def set_rate(self):
        self.output["rate"] = int(self.txt_ent.get())
        self.output_label["text"] = "Output\nRate: {} Color: {}".format(self.output["rate"],self.output["comp"])

class Application(tk.Frame):
    def time_step(self):
        for item in self.node_li:
            try:
                item.tick()
            except AttributeError as err:
                print("Error no tick: " + err)
        self.master.after(100, self.time_step)

    def __init__(self, master=None):
        tk.Frame.__init__(self,master)
        self.style = ttk.Style()
        self.style.map("A.TButton",
                  foreground=[('pressed', 'red'), ('active', 'blue')],
                  background=[('pressed', '!disabled', 'black'), ('active', 'white')]
                  )
        self.press_count = 0
        self.master = master
        # set window size
        # self.master.geometry("300x300")
        self.pack()
        self.createWidgets()
    #self.after(1000,self.time_step)

    def createWidgets(self):
        self.hi_there = ttk.Button(self)
        self.hi_there["text"] = "time step"
        self.hi_there["style"] = "A.TButton"
        self.hi_there["command"] = self.time_step
        self.hi_there.pack(side="top")
        
        self.cs = ColorSource(self,"Source")
        self.cl1 = ColorTank(self,self.cs.output,"Cl1")
        self.cl2 = ColorShifter(self,self.cl1.output,"Clite2")
        self.cl3 = ColorTank(self,self.cl2.output,"Cl3")
        self.cl4 = ColorTank(self,self.cl3.output,"Cl4")
        self.cl5 = ColorTank(self,self.cl4.output,"Cl5")
        self.node_li = [self.cs,
                        self.cl1,
                        self.cl2,
                        self.cl3,
                        self.cl4,
                        self.cl5]
        self.cs.pack()
        self.cl1.pack()
        self.cl2.pack()
        self.cl3.pack()
        self.cl4.pack()
        self.cl5.pack()

def clamp(x): return max(0, min(x, 255))
def clamp_n(x): return min(255, max(x, 0))


def normalize_tup(tu):
    mag = max(tu) - min(tu)
    tu = tuple(i/mag for i in tu)
    print(tu)

def mod_print():
    print("This is from main")

def run(options,args):
    root = tk.Tk()
    app = Application(master=root)
    app.mainloop()
    print(options, args)

def parse_command_line():
    parser = OptionParser()
    parser.add_option("-f", "--file", dest="filename", help="read data from FILENAME")
    parser.add_option("-v", "--verbose", action="store_true", dest="verbose")
    parser.add_option("-q", "--quiet", action="store_false", dest="verbose")
    
    (options, args) = parser.parse_args()
    # handle command line arguments
    #    if len(args) != 1:
    #        parser.error("incorrect number of arguments")
    if options.verbose:
        print("reading %s..." % options.filename)
        print(options,args)
    return(options, args)

def main():
    (options, args) = parse_command_line()
    run(options, args)

if __name__ == "__main__":
    main()